﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestGen
{
	public static class Program
	{
		/////////////////////////////////
		//Locations to find various resources
		public static string ROOT_STRING = BaseDirString();

		private static string BaseDirString()
		{
			String cp = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
			int cmdloc = cp.LastIndexOf(@"jackalope");
			if(cmdloc != -1)
			{
				cmdloc = cp.IndexOf(@"\", cmdloc);
				cmdloc = cp.IndexOf(@"\", cmdloc + 1);
			}

			if(cmdloc == -1)
			{
				Console.WriteLine("Cannot move outside of jackalope directory!!!");
				System.Environment.Exit(1);
			}

			string rp = cp.Substring(0, cmdloc + 1);
			return rp;
		}

		public static string TEST_DIR = ROOT_STRING + @"Data\Tests";
		public static string RESULT_DIR_FULLCTX = ROOT_STRING + @"Data\TestResults\";
		public static string DUMP_DIR = ROOT_STRING + @"Data\";
		public static string SERIALIZE_DIR = ROOT_STRING + @"Data\ResultsDump";

		/////////////////////////////////
		//Files for testing and evaluation

		//Simple tests
		public static string FilterMarkSumExe = TEST_DIR + @"\Simple\FilterMarkSumExample\FilterMarkSumExample\bin\Debug\FilterMarkSumExample.exe";
		public static string TListExe = TEST_DIR + @"\Simple\TList\TList\bin\Debug\TList.exe";
		public static string RListExe = TEST_DIR + @"\Simple\RList\RList\bin\Debug\RList.exe";
		public static string TreeExe = TEST_DIR + @"\Simple\Tree\Tree\bin\Debug\Tree.exe";
		public static string MRaytracerExe = TEST_DIR + @"\Simple\MRaytracer\MRaytracer\bin\Debug\MRaytracer.exe";
		public static string LibQuantumExe = TEST_DIR + @"\Simple\LibQuantum\LibQuantum\bin\Debug\LibQuantum.exe";

		public static string StructAndFuncExe = TEST_DIR + @"\Simple\DelegateTests\DelegateTests\bin\Debug\DelegateTests.exe";
		public static string SetAndDictExe = TEST_DIR + @"\Simple\SetAndDict\SetAndDict\bin\Debug\SetAndDict.exe";

		//csolden tests
		public static string BHExe = TEST_DIR + @"\Olden\BH\BH\bin\Debug\BH.exe";
		public static string BiSortExe = TEST_DIR + @"\Olden\BiSort\BiSort\bin\Debug\BiSort.exe";
		public static string Em3dExe = TEST_DIR + @"\Olden\Em3d\Em3d\bin\Debug\Em3d.exe";
		public static string HealthExe = TEST_DIR + @"\Olden\Health\Health\bin\Debug\Health.exe";
		public static string PerimeterExe = TEST_DIR + @"\Olden\Perimeter\Perimeter\bin\Debug\Perimeter.exe";
		public static string PowerExe = TEST_DIR + @"\Olden\Power\Power\bin\Debug\Power.exe";
		public static string TSPExe = TEST_DIR + @"\Olden\TSP\TSP\bin\Debug\TSP.exe";

		//csspec tests
		public static string DBExe = TEST_DIR + @"\Spec\DB\DB\bin\Debug\DB.exe";
		public static string SpecRaytraceExe = TEST_DIR + @"\Spec\SpecRaytracer\SpecRaytracer\bin\Debug\SpecRaytracer.exe";

		//large tests
		public static string LUIndexExe = TEST_DIR + @"\Large\luindex\bin\NLucene.exe";
		public static string LUSearchExe = TEST_DIR + @"\Large\lusearch\bin\NLucene2.exe";
		public static string RunAbsExe = TEST_DIR + @"\Large\HeapAbs\HeapAbs\bin\Debug\HeapAbs.exe";

		/////////////////////////////////
		//Quick flags to set to control default behaviors, easier than build flags or cmdline params for timing tests, regenerating desired output info, etc.
		private static bool RunInSingleMode = true;
		private static string SingleFileToAnalyze = BHExe;

		public static void Main(string[] args)
		{
			if(RunInSingleMode)
			{
				string exeasm = (args.Length != 0 ? args[0] : SingleFileToAnalyze);
				BuildTestsForSingleExecFile(exeasm);
			}
			else
				RunAllFiles();
		}

		private static void RunAllFiles()
		{
			RunAllFilesDoSingle(FilterMarkSumExe);
			RunAllFilesDoSingle(TListExe);
			RunAllFilesDoSingle(RListExe);
			RunAllFilesDoSingle(TreeExe);
			RunAllFilesDoSingle(MRaytracerExe);
			RunAllFilesDoSingle(LibQuantumExe);

			RunAllFilesDoSingle(BHExe);
			RunAllFilesDoSingle(BiSortExe);
			RunAllFilesDoSingle(Em3dExe);
			RunAllFilesDoSingle(HealthExe);
			RunAllFilesDoSingle(PerimeterExe);
			RunAllFilesDoSingle(PowerExe);
			RunAllFilesDoSingle(TSPExe);

			RunAllFilesDoSingle(DBExe);
			RunAllFilesDoSingle(SpecRaytraceExe);

			RunAllFilesDoSingle(StructAndFuncExe);
			RunAllFilesDoSingle(SetAndDictExe);

			RunAllFilesDoSingle(LUIndexExe);

			Console.WriteLine("Skipping LUSearch because it serializes a lot of data!!");
			//RunAllFilesDoSingle(LUSearchExe);

			//RunAllFilesDoSingle(RunAbsExe);
		}

		private static void RunAllFilesDoSingle(string fname)
		{
			string baseExec = System.IO.Path.GetFileName(fname);

			string hs = "*********** " + baseExec + " ***********";
			string hhs = "";
			for(int kk = 0; kk < hs.Length; ++kk)
				hhs += "*";
			Console.WriteLine("\n\n" + hhs + "\n" + hs + "\n");

			BuildTestsForSingleExecFile(fname);
		}

		public static void BuildTestsForSingleExecFile(string exeasm)
		{
			System.Diagnostics.Stopwatch timerload = new System.Diagnostics.Stopwatch();
			timerload.Start();

			SimpleIR.IRProgram p = CCITranslator.CCIExtractor.Extract(exeasm, ROOT_STRING);
			p.LoadTypeInfo();
			p.PreProcLinkAndSimplify();

			p.BuildT1T2();

			timerload.Stop();

			RgnAnalyzer.GlobalAnalysisState.LoadProg(p, DUMP_DIR, SERIALIZE_DIR);

			//do the analysis
			System.Diagnostics.Stopwatch timeranalyze = new System.Diagnostics.Stopwatch();
			timeranalyze.Start();
			RgnAnalyzer.GlobalAnalysisState.AnalyzeMain(true);
			timeranalyze.Stop();

			//time post processing
			System.Diagnostics.Stopwatch timerpost = new System.Diagnostics.Stopwatch();
			timerpost.Start();

			Console.WriteLine("Computing Completed Information (this may take a bit of time).");
			PInfoModel.CompleteAnalysisInfoMethodContext.InitializeProgPointInfoTables();
			PInfoModel.CompleteAnalysisInfoForProgram fpinfo = RgnAnalyzer.GlobalAnalysisState.ComputeFullAnalysisInfo(false);

			////
			//Clean up
			PInfoModel.CompleteAnalysisInfoMethodContext.CleanUpProgPointInfoTables();
			timerpost.Stop();

			PInfoModel.CompleteAnalysisInfoMethod pcm = fpinfo.MethodInfo.Values.First((PInfoModel.CompleteAnalysisInfoMethod ccm) => ccm.InvokeID.DefInClass.BaseTypeName.Equals("Body") && ccm.InvokeID.Sig.InvokeName.Equals("walkSubTree"));
			
			List<TGenConstraint> constraints = new List<TGenConstraint>();
			List<Tuple<string, string>> fixedvars = new List<Tuple<string,string>>();
			List<string> paramargs = new List<string>();
			ModelSizeInfo.ComputeConstraintSets(pcm.SummaryInState, constraints, fixedvars, paramargs);

			TestGen.HeapGenerate hgen = new HeapGenerate(p.MethodBodyTable.GetBodyForInvokeExactSigMatch(pcm.InvokeID), pcm.SummaryInState, constraints, fixedvars, paramargs);
			string result = hgen.BuildConstructor("empty_params", "invoke_method", 0);

			string genheap = pcm.SummaryInState.DGMLDumpPModel(-1);
			string rfile = System.IO.Path.Combine(DUMP_DIR, "genheap.dgml");
			System.IO.File.WriteAllText(rfile, genheap);

			string ofile = System.IO.Path.Combine(DUMP_DIR, "prog.test");
			System.IO.File.WriteAllText(ofile, result);
		}
	}
}
